import cookielib, xmlrpclib, urllib2

version = '0.1'

class BugzillaTransport(xmlrpclib.Transport):
	def __init__(self, url, cookiejar):
		xmlrpclib.Transport.__init__(self)
		self.cookiejar = cookiejar
		if url.startswith('https:'):
			self.scheme = 'https'
		else:
			self.scheme = 'http'

	def send_cookies(self, connection, cookie_request):
		# Let the cookiejar figure out what cookies are appropriate
		self.cookiejar.add_cookie_header(cookie_request)
		# Pull the cookie headers out of the request object...
		cookielist = list()
		for h, v in cookie_request.header_items():
			if h.startswith('Cookie'):
				cookielist.append([h,v])
		# and put them over the connection
		for h, v in cookielist:
			connection.putheader(h, v)

	# This is the same request() method from xmlrpclib.Transport,
	# with a couple additions noted below
	def request(self, host, handler, request_body, verbose=0):
		h = self.make_connection(host)
		if verbose:
			h.set_debuglevel(1)
		# ADDED: construct the URL and Request object for proper cookie handling
		request_url = "%s://%s/" % (self.scheme, host)
		cookie_request  = urllib2.Request(request_url)
		self.send_request(h, handler, request_body)
		self.send_host(h, host)
		self.send_cookies(h,cookie_request) # ADDED. creates cookiejar if None.
		self.send_user_agent(h)
		self.send_content(h, request_body)
		errcode, errmsg, headers = h.getreply()
		# ADDED: parse headers and get cookies here
		# fake a response object that we can fill with the headers above
		class FakeResponse:
			def __init__(self, headers):
				self.headers = headers
			def info(self):
				return self.headers
		cookie_response = FakeResponse(headers)
		# Okay, extract the cookies from the headers
		self.cookiejar.extract_cookies(cookie_response, cookie_request)
		# And write back any changes
		if hasattr(self.cookiejar, 'save'):
			self.cookiejar.save(self.cookiejar.filename)
		if errcode != 200:
			raise xmlrpclib.ProtocolError(
				host + handler,
				errcode, errmsg,
				headers
			)
		self.verbose = verbose
		try:
			sock = h._conn.sock
		except AttributeError:
			sock = None
		return self._parse_response(h.getfile(), sock)

class ApiObject(object):
	__fields__ = []

	def __init__(self, bz, data = None):
		self.bz = bz
		if data:
			for f in self.__fields__:
				setattr(self, f, data[f])

	@classmethod
	def build_list(cls, bz, result):
		res = []
		for r in result:
			res.append(cls(bz, data = r))
		return res

class Product(ApiObject):
	__fields__ = ['id', 'name', 'description', 'internals']

	@classmethod
	def get_list(cls, bz):
		resp = bz.rpc.Product.get_accessible_products()
		data = bz.rpc.Product.get_products(resp)
		return cls.build_list(bz, data['products'])

	def get_components(self):
		resp = self.bz.rpc.Bug.legal_values({'product_id': self.id, 'field': 'component'})
		return resp['values']
	components = property(get_components, None)

	def get_versions(self):
		resp = self.bz.rpc.Bug.legal_values({'product_id': self.id, 'field': 'version'})
		return resp['values']
	versions = property(get_versions, None)

	def get_milestones(self):
		resp = self.bz.rpc.Bug.legal_values({'product_id': self.id, 'field': 'target_milestone'})
		return resp['values']
	milestones = property(get_milestones, None)

class Bug(ApiObject):
	__fields__ = ['id', 'alias', 'summary', 'creation_time', 'last_change_time', 'internals']

class Bugzilla(object):
	def __init__(self, url, user = None, password = None, cookie_file = None):
		self.url = url
		self.user = user
		self.password = password
		if cookie_file:
			self.cookiejar = cookielib.MozillaCookieJar()
			self.cookiejar.load(cookie_file)
			self.cookiejar.filename = cookie_file
		else:
			self.cookiejar = cookielib.CookieJar()
		self.transport = BugzillaTransport(self.url, self.cookiejar)
		self.rpc = xmlrpclib.ServerProxy(self.url, self.transport)

	def get_version(self):
		return self.rpc.Bugzilla.version()['version']

	def get_timezone(self):
		return self.rpc.Bugzilla.timezone()['timezone']

	def login(self):
		return self.rpc.User.login({'login': self.user, 'password': self.password})

	def logout(self):
		return self.rpc.User.logout()

	def get_products(self, product_id = None):
		if not product_id:
			return Product.get_list(self)
		else:
			if type(product_id) is int:
				single = True
				product_id = (product_id, )
			else:
				single = False
			products = Product.build_list(self, self.rpc.Product.get_products({'ids': product_id})['products'])
			if single:
				return products[0]
			else:
				return products
	products = property(get_products, None)

	def get_bug_oses(self):
		resp = self.bz.rpc.Bug.legal_values({'field': 'op_sys'})
		return resp['values']

	def get_bug_platforms(self):
		resp = self.bz.rpc.Bug.legal_values({'field': 'platform'})
		return resp['values']

	def get_bug_priorities(self):
		resp = self.bz.rpc.Bug.legal_values({'field': 'priority'})
		return resp['values']

	def get_bug_severities(self):
		resp = self.bz.rpc.Bug.legal_values({'field': 'severity'})
		return resp['values']

	def get_bugs(self, bug_id):
		if type(bug_id) is int:
			single = True
			bug_id = (bug_id, )
		else:
			single = False
		bugs = Bug.build_list(self, self.rpc.Bug.get_bugs({'ids': bug_id})['bugs'])
		if single:
			return bugs[0]
		else:
			return bugs

	def file_bug(self, **kwargs):
		resp = self.rpc.Bug.create(kwargs)
		return self.get_bug(resp['id'])

